package rjeutsky;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

import rjeutsky.database.interfaces.Repository;
import rjeutsky.database.jdbc.Connector;
import rjeutsky.database.jdbc.JDBCRepository;
import rjeutsky.models.Publication;
import rjeutsky.models.Subscription;
import rjeutsky.models.User;
import rjeutsky.models.UserRole;
import rjeutsky.validators.PublicationValidator;
import rjeutsky.validators.SubscriptionValidator;
import rjeutsky.validators.UserValidator;
import rjeutsky.validators.interfaces.Validator;

public class ApplicationController {
	
	protected Repository repository;
	protected Connection connection;
	
	public ApplicationController() {
		try {
			initializeRepository();
		} catch (FileNotFoundException e) {
			System.out.println("configuration file not found");
		} catch (ClassNotFoundException e) {
			System.out.println("sql driver not found");
		} catch (IOException e) {
			System.out.println("settings cannot be read");
		} catch (SQLException e) {
			System.out.println(e.getMessage());
		}
	}
	
	protected void initializeRepository() throws SQLException, FileNotFoundException, ClassNotFoundException, IOException {
		connection = new Connector().getConnection();
		repository = new JDBCRepository(connection);
	}
	
	public void finishApplication() throws SQLException {
		connection.close();
	}
	
	/**
	 * 
	 * @return User object, if login succeeded, null otherwise
	 */
	public User getUser(String login, String password) {
		try {
			User user = repository.getUserByLogin(login);
			if (user != null && user.getPassword().equals(password)) {
				return user;
			}
		} catch (SQLException ex) {
			ReportSqlError(ex);
		}
		
		return null;
	}
	
	public User getUser (long userId) {
		try {
			return repository.getReaderRepository().read(userId);
		} catch (SQLException e) {
			ReportSqlError(e);
		}
		
		return null;
	}
	
	public void createUser(User newUser) {
		try {
			newUser.setSalt("");
			repository.getReaderRepository().create(newUser);
		} catch (SQLException e) {
			ReportSqlError(e);
		}
	}
	
	public Validator<User> getUserValidator() {
		return new UserValidator(repository);
	}
	
	public List<Publication> getPublications() {
		try {
			return repository.getPublicationRepository().query();
		} catch (SQLException e) {
			ReportSqlError(e);
		}
		
		return new LinkedList<Publication>();
	}
	
	public void createPublication(Publication publication) {
		try {
			repository.getPublicationRepository().create(publication);
		} catch (SQLException e) {
			ReportSqlError(e);
		}
	}
	
	public void updatePublication(Publication publication) throws SQLException {
		repository.getPublicationRepository().update(publication);
	}
	
	public Validator<Publication> getPublicationValidator() {
		return new PublicationValidator();
	}
	
	public List<Subscription> getUnpayedSubscriptions() {
		try {
			return repository.getUnpayedSubscriptions();
		} catch (SQLException e) {
			ReportSqlError(e);
		}
		
		return new LinkedList<Subscription>();
	}
	
	public List<Publication> getSubscriptionPublications(Subscription subscription) {
		try {
			return repository.getSubscriptionPublications(subscription);
		} catch (SQLException e) {
			ReportSqlError(e);
		}
		
		return new LinkedList<Publication>();
	}
	
	public long GetPaymentSum(Collection<Long> ids) throws SQLException {
		List<Publication> publications = new LinkedList<Publication>();
		for (long id : ids) {
			Publication publication = repository.getPublicationRepository().read(id);
			if (publication != null) {
				publications.add(publication);
			}
		}
		
		return repository.getPredictedPaymentAmount(publications);
	}
	
	public long GetPaymentSum(Subscription subscription) throws SQLException {
		return repository.getPaymentAmount(subscription);
	}
	
	public void createSubscription(Subscription subscription, Collection<Long> publicationIds) {
		try {
			repository.getSubscriptionRepository().create(subscription);
			for (long id : publicationIds) {
				Publication publication = repository.getPublicationRepository().read(id);
				if (publication != null) {
					repository.addPublicationToSubscription(publication, subscription);
				}
			}
		} catch (SQLException ex) {
			ReportSqlError(ex);
		}
	}
	
	public Validator<Subscription> getSubscriptionValidator() {
		return new SubscriptionValidator();
	}
	
	public void processPayment(Subscription subscription) throws SQLException {
		repository.processPayment(subscription);
	}
	
	public List<User> getUsers() {
		try {
			return repository.getReaderRepository().query();
		} catch (SQLException e) {
			ReportSqlError(e);
		}
		
		return new LinkedList<User>();
	}
	
	public List<Publication> getUserPublications (User user) {
		try {
			return repository.getPublicationsByReader(user);
		} catch (SQLException e) {
			ReportSqlError(e);
		}
		
		return new LinkedList<Publication>();
	}
	
	public boolean checkIsAdmin(User user) {
		try {
			List<UserRole> roles = repository.getUserRoles(user);
			for(UserRole role : roles) {
				if (role.getName().equals(UserRole.ADMIN)) {
					return true;
				}
			}
		} catch (SQLException e) {
			ReportSqlError(e);
		}
		
		return false;
		
	}
	
	public Publication getPublication(long publicationId) {
		try {
			return repository.getPublicationRepository().read(publicationId);
		} catch (SQLException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	public Subscription getSubscription(long subscriptionId) {
		try {
			return repository.getSubscriptionRepository().read(subscriptionId);
		} catch (SQLException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	public void ReportSqlError (SQLException ex) {
		//System.out.println("An sql error has occured");
		System.out.println(ex.getMessage());
	}
	
}
